// 查询内存中所有so文件
function hook_all_so() {
    var process_Obj_Module_Arr = Process.enumerateModules();
    for (var i = 0; i < process_Obj_Module_Arr.length; i++) {
        //包含"lib"字符串的
        if (process_Obj_Module_Arr[i].path.indexOf("lib") != -1) {
            console.log("模块名称:", process_Obj_Module_Arr[i].name);
            // console.log("模块地址:",process_Obj_Module_Arr[i].base);
            // console.log("大小:",process_Obj_Module_Arr[i].size);
            // console.log("文件系统路径",process_Obj_Module_Arr[i].path);

            var libname = process_Obj_Module_Arr[i].name
            frida_Module_import(libname)
        }
    }
}

function frida_Module_import(libname) {
    Java.perform(function () {
        const hooks = Module.load(libname);
        var Imports = hooks.enumerateExports();
        for (var i = 0; i < Imports.length; i++) {
            if (Imports[i].name.indexOf('Java') != -1) {
                //函数类型
                console.log("type:", Imports[i].type);
                //函数名称
                console.log("name:", Imports[i].name);
                //属于的模块
                console.log("module:", Imports[i].module);
                //函数地址
                console.log("address:", Imports[i].address);
            }
        }
    });
}

// 查看依次加载了哪些so文件，可以用来找哪个so中做了反调试
function hook_lib() {
    var dlopen = Module.findExportByName(null, "dlopen");
    var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");

    Interceptor.attach(dlopen, {
        onEnter: function (args) {
            var path_ptr = args[0];
            var path = ptr(path_ptr).readCString();
            console.log("[dlopen:]", path);
        },
        onLeave: function (retval) {

        }
    });

    Interceptor.attach(android_dlopen_ext, {
        onEnter: function (args) {
            var path_ptr = args[0];
            var path = ptr(path_ptr).readCString();
            console.log("[dlopen_ext:]", path);
        },
        onLeave: function (retval) {

        }
    })
}

function hook_RegisterNatives() {
    // 列举 libart.so 中的所有导出函数（成员列表）
    var symbols = Module.enumerateSymbolsSync("libart.so");
    // 获取 RegisterNatives 函数的内存地址，并赋值给addrRegisterNatives
    var addrRegisterNatives = null;
    for (var i = 0; i < symbols.length; i++) {
        var symbol = symbols[i]; // 成员对象

        // _ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi
        // 方式1：
        if (symbol.name.indexOf("art") >= 0 &&
            symbol.name.indexOf("JNI") >= 0 &&
            symbol.name.indexOf("RegisterNatives") >= 0 &&
            symbol.name.indexOf("CheckJNI") < 0) {
            addrRegisterNatives = symbol.address;
            console.log("RegisterNatives is at ", symbol.address, symbol.name);
        }

        // 方式2：
        var name = "_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi";
        if (symbol.name.indexOf("art") >= 0) {
            if (symbol.name.indexOf(name) >= 0) {
                addrRegisterNatives = symbol.address;
            }
        }
    }

    if (addrRegisterNatives != null) {
        //      这里写某函数的内存地址
        Interceptor.attach(addrRegisterNatives, {
            onEnter: function (args) {
                var env = args[0]; // jni对象 env
                var java_class = args[1]; // 类 jclass
                var class_name = Java.vm.tryGetEnv().getClassName(java_class);
                //console.log(class_name); //得到类名
                // 只有类名为com.xxxx，才打印输出
                var taget_class = "com.gdufs.xman.MyApp";
                if (class_name === taget_class) {
                    console.log("\n[RegisterNatives] method_count:", args[3]);
                    // args[2] 就是动态注册的对应关系。
                    // ptr是new NativePointer(s) 的缩写。(C语言中的指针)
                    var methods_ptr = ptr(args[2]);
                    var method_count = parseInt(args[3]);

                    for (var i = 0; i < method_count; i++) {
                        // Java中函数名字的
                        var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
                        // 参数和返回值类型
                        var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
                        // C中的函数指针
                        var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));

                        var name = Memory.readCString(name_ptr); // 读取java中函数名
                        var sig = Memory.readCString(sig_ptr); // 参数和返回值类型 e.g.(Ljava/lang/String;)Ljava/lan/String
                        var find_module = Process.findModuleByAddress(fnPtr_ptr); // 根据C中函数指针获取模块
                        // console.log("111", fnPtr_ptr)
                        // 偏移量(hex) = fnPtr_ptr - 模块基地址
                        var offset = ptr(fnPtr_ptr).sub(find_module.base)
                        // console.log("[RegisterNatives] java_class:", class_name);
                        console.log("name:", name, "sig:", sig, "module_name:", find_module.name, "offset:", offset);
                    }
                }
            }
        });
    }
}

function hook_init() {
    // 寻找linker
    var linker = Process.findModuleByName("linker");
    var call_function_addr = null;
    // 遍历linker的符号
    var symbols = linker.enumerateSymbols();
    for (var i = 0; i < symbols.length; i++) {
        // 取到名称
        var name = symbols[i].name;
        // 如果名称是call_function，则得到该地址并返回
        if (name.indexOf("call_function") >= 0) {
            call_function_addr = symbols[i].address;
            break;
        }
    }
    console.log("call_function_addr->", call_function_addr);
    // 来附加call_function函数
    Interceptor.attach(call_function_addr, {
        onEnter: function (args) {
            // 进入函数的时候判断要执行的函数地址末尾是否是3dd
            if (String(args[1]).indexOf("3dd") >= 0) {
                console.log("found");
                // 如果根据函数地址找到了初始化函数，则对其进行hook，置空处理
                Interceptor.replace(
                    args[1],
                    new NativeCallback(
                        function (s, addr, rp) {
                            console.log("destory")
                        },
                        "int",
                        []
                    )
                );
            }
        },
        onLeave: function (retval) {

        }
    })

}


function main() {
    console.log("==== 0")

    Java.perform(function () {
        // hook_init()
        hook_RegisterNatives()

    })
}

setImmediate(main)